//ode 1 ivp
//$Id: ode1ivp.h 441 2010-04-09 17:27:20Z Oleg.Bulychov $
#pragma once

#include "src/heo/include/lf_endl.h"
#include "src/heo/include/random.h"
#include "src/heo/include/reflection.h"
#include "src/heo/include/solution.h"
#include "src/heo/include/optimization_direction.h"
#include "src/heo/include/transmit_vector.h"

struct ODE1IVP_Config
{
    size_t   limit_output_;
    int      precision_;
    double   eps_;

    double   xa_;
    double   xb_;
    double   y0_;
    size_t   n_;

    static char const* get_Name() { return "ode1ivp"; }

    template<class V>
    void accept(V& v)
    {
        v(VAR_(limit_output),               20);
        v(VAR_(precision),                   3);
        v(VAR_(eps),                       0.1);
        v(VAR_(xa),                        0.0);
        v(VAR_(xb),                        1.0);
        v(VAR_(y0),                        1.0);
        v(VAR_(n),                          10);
    }
};
//__________________________________________________________________________________
struct ODE1IVP_Problem
{
    explicit ODE1IVP_Problem()
    {}

    static char const* get_Default_File_Name() { return ""; }

    template<class I, class E>
    bool read(I& in, E* env, uniform_random& rnd)
    {
        return false;
    }
};
//__________________________________________________________________________________
//__________________________________________________________________________________
class ODE1IVP_Solution
{
    //DISALLOW_COPY_AND_ASSIGN(ODE1IVP_Solution);
public:
    typedef double                  TCostType;
    typedef minimization<TCostType> TDirection;
protected:
    TCostType            cost_;
    bool                 changed_;
    double               h_;
    std::vector<double>  x_;
    std::vector<double>  y_;
public:
    explicit ODE1IVP_Solution(): cost_(0), changed_(false)
    {}

    ~ODE1IVP_Solution()
    {
    }

    template<class E>
    void init(E* env, uniform_random& rnd)
    {
        h_   = (env->cfg_.xb_ - env->cfg_.xa_) / env->cfg_.n_;

        x_.resize(env->cfg_.n_ + 1);
        for (size_t i = 0; i <= env->cfg_.n_; ++i)
            x_[i] = env->cfg_.xa_ + i * h_;

        y_.resize(env->cfg_.n_ + 1);
        y_[0] = env->cfg_.y0_;
    }

    template<class E>
    void generate(E* env, uniform_random& rnd)
    {
        for (size_t i = 1; i <= env->cfg_.n_; ++i) 
            y_[i] = y_[0] + env->cfg_.eps_ * (1 - 2 * rnd.next_Double()); // y_[0] - eps_ < y_[i] < y_[0] + eps_

        changed_ = true;
    }

    TCostType get_Cost() const
    {
        ASSERT_(!changed_);
        return cost_;
    }

    template<class E>
    void evaluate(E* env, uniform_random& rnd)
    {
        if (!changed_)
            return;

        cost_ = 0;
        double t;
        for (size_t i = 1; i <= env->cfg_.n_; ++i)
        {
            t = (y_[i] - y_[i-1])/h_ - x_[i] * y_[i]; 
            cost_ += t * t; 
        }


        changed_ = false;
    }

    void assign(ODE1IVP_Solution const& sol)
    {
        changed_ = sol.changed_;
        cost_    = sol.cost_;
        h_       = sol.h_;
        x_       = sol.x_;
        y_       = sol.y_;
    }

    template<class X>
    void copy_To(X& x) const
    {
        x.assign(*this);
    }

    template<class E>
    void print(std::ostream& os, E* env)
    {
        os << "x = ";
        for (size_t i = 0; i <= env->cfg_.n_; ++i)
        {
            os.precision(env->cfg_.precision_);
            os << std::fixed << x_[i] << " ";
            if (i > env->cfg_.limit_output_)
            {
                os << "...";
                break;
            }
        }

        os << lf << "y = ";
        for (size_t i = 0; i <= env->cfg_.n_; ++i)
        {
            os.precision(env->cfg_.precision_);
            os << std::fixed << y_[i] << " ";
            if (i > env->cfg_.limit_output_)
            {
                os << "...";
                break;
            }
        }

        os << lf
            << "cost: " << std::fixed << get_Cost() << lf;
    }

    template<class E>
    static bool read(E* env, std::string const& file_name, Solution_Pool<ODE1IVP_Solution>& pool)
    {
        return false;
    }

    template<class E>
    void write(E* env, std::string const& file_name, size_t id, size_t count)
    {
    }

    template<class V>
    void accept(V& v)
    {
        v(cost_);
        v(changed_);
        v(h_);
        v(x_);
        v(y_);
    }
};
//__________________________________________________________________________________

//EOF!

